#pragma once

#include <stack>
#include <optional>
#include <functional>
#include <odv/odvCore/Viewer.h>

#include <osg/ref_ptr>
#include <osg/Vec3>
#include <osg/Vec2i>
#include <osg/Vec4>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/observer_ptr>
#include <osg/MatrixTransform>

#include <osgEarthAnnotation/FeatureNode>
#include <osgEarthSymbology/Geometry>
#include <osgEarth/SpatialReference>

// 定义枚举和字符串的映射
#define ENUM_CALLBACK_MAPPING(XX) \
    XX(MapMouseMoveCallback, "MapMouseMoveCallback")\
	XX(MapMouseClickedCallback, "MapMouseClickedCallback")\
	XX(MapPointCallback, "MapPointCallback")\
	XX(MapSectionCallback, "MapSectionCallback")\
	XX(MapTimeCallback, "MapTimeCallback")\
	XX(MapMouseWheelClickedCallback, "MapMouseWheelClickedCallback")\

namespace appmodule{

	// 生成枚举类型
	enum class CallbackType {
#define DEFINE_ENUM_VALUE(name, str) name,
		ENUM_CALLBACK_MAPPING(DEFINE_ENUM_VALUE)
#undef DEFINE_ENUM_VALUE
	};

	// 生成映射表
	static const std::vector<std::pair<CallbackType, std::string>> s_CallbackTypeTable = { {
	#define DEFINE_MAPPING(name, str) {CallbackType::name, str},
		ENUM_CALLBACK_MAPPING(DEFINE_MAPPING)
	#undef DEFINE_MAPPING
	} };

	// 枚举转字符串函数
	inline std::optional<std::string> enumToString(CallbackType callback) {
		for (const auto& entry : s_CallbackTypeTable) {
			if (entry.first == callback) {
				return entry.second;
			}
		}
		return std::nullopt;
	}

	class MapMouseMoveCallback
	{
	public:
		MapMouseMoveCallback(int viewIndex);

		inline void setCallback(std::function<void(double, double, double, int)> func) { _callback = func; }

		inline void reset() { _callback = {}; }

		void operator()(odv::Viewer* viewer, odv::EventType eventType, odv::MouseButton button, int x, int y) ;

		// 经纬度转度分秒
		void convertToDMS(double decimalDegree, int& degrees, int& minutes, double& seconds);

	private:
		
		int _viewIndex{ -1 };
		
		//double lon, double lat, double altitude, int viewIndex
		std::function<void(double, double, double, int)> _callback;
	};


	// 获取当前正在工作的索引
	class MapMouseClickedCallback
	{
	public:
		MapMouseClickedCallback(int viewIndex);

		inline void setCallback(std::function<void(int)> func) { _mapClickedCallback = func; }

		void operator()(odv::Viewer* viewer, odv::EventType eventType, odv::MouseButton button, int x, int y) const;

		inline void reset() { _mapClickedCallback = {}; }

	private:
		int _viewIndex{ -1 };

		//_viewIndex
		std::function<void(int)> _mapClickedCallback;
	};

	// 鼠标滚轮滚动，获取视口宽度和高度
	class MapMouseWheelClickedCallback
	{
	public:
		MapMouseWheelClickedCallback(int viewIndex);

		inline void setCallback(std::function<void(int, float, float)> func) { _mapWheelCallback = func; }

		void operator()(odv::Viewer* viewer, odv::EventType eventType, odv::MouseButton button, int x, int y) const;

		inline void reset() { _mapWheelCallback = {}; }

	private:
		int _viewIndex{ -1 };

		//_viewIndex
		std::function<void(int, float, float)> _mapWheelCallback;
	};

	// 剖面 单点
	class MapPointCallback
	{
	public:
		MapPointCallback(std::shared_ptr<odv::Viewer> viewer, int viewIndex);
		virtual ~MapPointCallback();

		inline void setCallback(std::function<void(double, double, int)> func) { _callback = func; }
		
		inline void reset() { _callback = {}; }

		void operator()(odv::Viewer* viewer, odv::EventType eventType, odv::MouseButton button, int x, int y) ;

		void startCallback();

		void stopCallback();

	protected:
		void addPoint(const osg::Vec3d& p);
		void updatePoint(const osg::Vec3d& p);
		void removePoint();

	private:
		int _viewIndex{ -1 };

		// lon lat viewIndex
		std::function<void(double, double, int)> _callback;

		std::optional<osg::Vec2i> _pushedCoords;

		osg::ref_ptr<osgEarth::SpatialReference> _wgs84;
		std::weak_ptr<odv::Viewer> _viewer;
		osg::ref_ptr<osg::MatrixTransform> _pointNode;
	};

	// 剖面 断面
	class MapSectionCallback
	{
	public:
		MapSectionCallback(std::shared_ptr<odv::Viewer> viewer, int viewIndex);
		~MapSectionCallback();

		using Point2D = std::pair<float, float>;
		inline void setCallback(std::function<void(Point2D, Point2D, int)> func) { _callback = func; }
		inline void reset() { _callback = {}; }

		void operator()(odv::Viewer* viewer, odv::EventType eventType, odv::MouseButton button, int x, int y) ;

		void startCallback();

		void stopCallback();

	protected:
		void addLine(const osg::Vec3& p1, const osg::Vec3& p2);
		void updateLine(const osg::Vec3& p1, const osg::Vec3& p2);
		void removeLine();

	private:
		// lon lat viewIndex
		int _viewIndex{ -1 };

		std::function<void(Point2D, Point2D, int)> _callback;

		std::weak_ptr<odv::Viewer> _viewer;
		osg::ref_ptr<osg::Geode> _lineNode;
		std::stack<osg::Vec3d> _points;
		std::optional<osg::Vec2i> _pushedCoords;
	};

	// 时序分析
	class MapTimeCallback : public MapPointCallback
	{
	public:
		MapTimeCallback(std::shared_ptr<odv::Viewer> viewer, int viewIndex);
		virtual ~MapTimeCallback();
	};
}
